home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Milan_1991 / Devcon91.1 / Libraries / Intuition / other_examples / CustGad / dialgadget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  9.2 KB  |  394 lines

  1. /* dial custom gadget implementation    */
  2.  
  3. /* MAKE SURE YOU COMPILE THIS FILE WITH STACK CHECKING TURNED OFF.    */
  4.  
  5. /*
  6. Copyright (c) 1989 Commodore-Amiga, Inc.
  7.  
  8. Executables based on this information may be used in software
  9. for Commodore Amiga computers. All other rights reserved.
  10. This information is provided "as is"; no warranties are made.
  11. All use is at your own risk, and no liability or responsibility
  12. is assumed.
  13. */
  14.  
  15. /*
  16.  * Limitations:
  17.  *    no RELWIDTH/RELHEIGHT (uses Width/Height)
  18.  *    no ActivateGadget() or manual toggling of SELECTED 
  19.  *    Image rendering only, no SelectImage.
  20.  */
  21.  
  22. #include "math.h"
  23. #include "sysall.h"
  24.  
  25. struct Gadget    *CreateGadget();
  26.  
  27. #define D( x )    ;    /* debugging: on 'x', off ';'    */
  28.  
  29. #define DGAVECS    (6)    /* area info vectors for needle    */
  30.  
  31. /*** black box dial gadget data ***/
  32. struct DialInfo {
  33.     WORD    coordX;        /* ray vector of needle            */
  34.     WORD    coordY;
  35.     WORD    baseX;        /* vector for base of needle        */
  36.     WORD    baseY;
  37.     struct AreaInfo    ainfo;
  38.     struct TmpRas    tmpras;
  39.     UBYTE    abuffer[ DGAVECS * 5 ];
  40. };
  41. #define DI( g )     ( (struct DialInfo *) (g)->SpecialInfo )
  42.  
  43. #define BASEFACTOR    (10)    /* relative width of needle        */
  44. #define NEEDLEPEN    (1)    /* pen color of needle            */
  45. #define CENTER(dim)    (((dim) - 1)/2)
  46.  
  47. /*** hook implementations ***/
  48. /* forward in this file    */
  49. ULONG    dial_Dispatch();    /* vectors off to the others    */
  50. ULONG    dial_render();
  51. ULONG    dial_handleinput();
  52.  
  53. /* see StrDemo/strhooks.c for more info on this
  54.  * particular implementation of a Hook callback
  55.  * asm-to-C interface routine.
  56.  */
  57. ULONG __saveds __asm
  58. hookEntry( register __a0 struct Hook *hookptr,
  59.     register __a2 void    *object,
  60.     register __a1 void    *message )
  61. {
  62.     D( kprintf("hookEntry\n"));
  63.     return ( (*hookptr->h_SubEntry)( hookptr, object, message ) );
  64. }
  65.  
  66. /* interface to get my dispatcher called by Intuition.
  67.  * this hook can be shared between several dial gadgets
  68.  */
  69. struct Hook dialhook =  { {0,0}, hookEntry, dial_Dispatch, 0 };
  70.  
  71. struct Gadget    *
  72. CreateDialGadget( id, im )
  73. struct Image    *im;
  74. {
  75.     struct Gadget    *g;
  76.     struct DialInfo    *di;
  77.     UBYTE        *tmpraster;
  78.     int            rassize;
  79.  
  80.     D( printf( "CDG: id: %lx, im %lx\n", id, im ) );
  81.  
  82.     if ( g = CreateGadget( im->Width, im->Height, id, NULL,
  83.         sizeof ( struct DialInfo ) ) )
  84.     {
  85.     di = DI( g );
  86.  
  87.     g->GadgetType = CUSTOMGADGET;
  88.     g->Flags |= GADGIMAGE;
  89.     g->MutualExclude = (ULONG) &dialhook;
  90.     g->GadgetRender = (APTR) im;
  91.  
  92.     SetDialCoords( g, 0, 1 );    /* initially "north"    */
  93.  
  94.     /* need to set up a temp raster for a dial gadget
  95.      * as well as AreaInfo.
  96.      * could probably arrange to share tmp rasters between
  97.      * dial gadgets no problem, via a SetDialGadgetTmpRaster()
  98.      * function call
  99.      */
  100.     InitArea( &di->ainfo, di->abuffer, DGAVECS );
  101.  
  102.     rassize = RASSIZE( (long) im->Width, (long) im->Height );
  103.     if (  tmpraster = (UBYTE *) AllocMem( rassize, MEMF_CHIP ) )
  104.     {
  105.         InitTmpRas( &di->tmpras, tmpraster, rassize );
  106.     }
  107.     else    /* abort    */
  108.     {
  109.         D( printf("CDG: couldn't get tmpraster size: %d\n", rassize ));
  110.         FreeGadgets( g );
  111.         g = NULL;
  112.     }
  113.     }
  114.  
  115.     return ( g );
  116. }
  117.  
  118. DeleteDialGadget( g )
  119. struct Gadget    *g;
  120. {
  121.     struct TmpRas    *tmpras = &DI( g )->tmpras;
  122.  
  123.     /* free off tmp raster    */
  124.     FreeMem( tmpras->RasPtr, tmpras->Size );
  125.  
  126.     /* delete gadget, special info, ... */
  127.     g->NextGadget = NULL;
  128.     FreeGadgets( g );
  129. }
  130.  
  131. /* returns TRUE if normalized coord values have changed    */
  132. SetDialCoords( g, x, y )
  133. struct Gadget    *g;
  134. {
  135.     WORD    oldx, oldy;
  136.     /* struct DialInfo    *di = DI( g ); */
  137.  
  138.     if ( !( x || y ) )
  139.     {
  140.         return ( SetDialCoords( g, 0, 1 ) );
  141.     }
  142.  
  143.     GetDialCoords( g, &oldx, &oldy );
  144.  
  145.     DI(g)->coordX = x;
  146.     DI(g)->coordY = y;
  147.     normalizeDialCoords( g );
  148.  
  149.     /* check for changes    */
  150.     GetDialCoords( g, &x, &y );
  151.  
  152.     return ( x != oldx || y != oldy );
  153. }
  154.  
  155. GetDialCoords( g, xp, yp )
  156. struct Gadget    *g;
  157. WORD    *xp;
  158. WORD    *yp;
  159. {
  160.     *xp = DI(g)->coordX;
  161.     *yp = DI(g)->coordY;
  162. }
  163.  
  164. static
  165. drawNeedle( rp, g, left, top )
  166. struct RastPort    *rp;
  167. struct Gadget *g;
  168. {
  169.     struct DialInfo    *di = DI( g );
  170.     long    centerX;
  171.     long    centerY;
  172.     struct TmpRas    *savetr;
  173.     struct AreaInfo    *saveai;
  174.  
  175.     /**** set up my tmpras/ainfo in Intuition's rastport    ****/
  176.     savetr = rp->TmpRas;
  177.     saveai = rp->AreaInfo;
  178.  
  179.     rp->TmpRas = &di->tmpras;
  180.     rp->AreaInfo = &di->ainfo;
  181.  
  182.     centerX = CENTER( g->Width );
  183.     centerY = CENTER( g->Height );
  184.  
  185.     SetAPen( rp, NEEDLEPEN );
  186.  
  187.     AreaMove( rp, left + centerX + di->baseX,
  188.              top + centerY + di->baseY );
  189.  
  190.     AreaDraw( rp, left + centerX - di->baseX,
  191.              top + centerY - di->baseY );
  192.  
  193.     AreaDraw( rp, left + centerX + di->coordX,
  194.              top + centerY + di->coordY );
  195.  
  196.     AreaEnd( rp );
  197.  
  198.     /*** restore Intuition's tmpras and ainfo    ***/
  199.     rp->TmpRas = savetr;
  200.     rp->AreaInfo = saveai;
  201. }
  202.  
  203. /*** internal number crunching ***/
  204.  
  205. struct FPoint    {
  206.     float    fX;
  207.     float    fY;
  208. };
  209.  
  210. /*
  211.  * converts values of coordX coordY to ray equivalent
  212.  * coordinates on ellipse boundary of dial.
  213.  * Never call this if the coords are both zero.
  214.  */
  215. static
  216. normalizeDialCoords( g )
  217. struct Gadget    *g;
  218. {
  219.     struct DialInfo    *di = DI( g );
  220.     struct FPoint    edge;
  221.     struct FPoint    base;
  222.     WORD        halfx = CENTER( g->Width );
  223.     WORD        halfy = CENTER( g->Height );
  224.     float        norm;
  225.     Point        ray;
  226.  
  227.     ray.x = di->coordX;
  228.     ray.y = di->coordY;
  229.  
  230.     norm =    (float) halfy * halfy * ray.x * (float) ray.x +
  231.             (float) halfx * halfx * ray.y * (float) ray.y;
  232.  
  233.     norm = sqrt( (double) norm );
  234.  
  235.     /* I forgot what clever math leads to this    */
  236.     edge.fX = (float) halfy * ray.x / norm;
  237.     edge.fY = (float) halfx * ray.y / norm;
  238.  
  239.     base.fX = edge.fY / BASEFACTOR;
  240.     base.fY = - edge.fX / BASEFACTOR;
  241.  
  242.     di->coordX = halfx * edge.fX;
  243.     di->coordY = halfy * edge.fY;
  244.  
  245.     di->baseX = halfx * base.fX;
  246.     di->baseY = halfy * base.fY;
  247. }
  248.  
  249. /**** the hook functions    ****/
  250. /* Note: these functions run as the input.device task.
  251.  * This means, among other things, that you can't do printf's
  252.  * to your own process's output window.
  253.  *
  254.  * Also, it is not safe to call Intuition or Graphics, except as
  255.  * documented for Intuition hook functions.
  256.  */
  257.  
  258. ULONG
  259. dial_Dispatch( hook, g, msg )
  260. struct Hook    *hook;    /* I don't have any use for this */
  261. struct Gadget    *g;
  262. ULONG        *msg;    /* only interested in HookID    */
  263. {
  264.     ULONG retval = 0;
  265.  
  266.     D( kprintf("\ndial_Dispatch. hook %lx, g %lx, msg: %lx id %ld\n",
  267.         hook, g, msg, *msg ) );
  268.  
  269.     switch ( (WORD) *msg )
  270.     {
  271.     case GM_HITTEST:
  272.     /*
  273.      * for now, if it's in the select box, we'll call it
  274.      * a hit.  (Might mask test or restrict to ellipse later.)
  275.      * Note that this function is only called if select box
  276.      * test has passed in Intuition.
  277.      */
  278.     retval = GMR_GADGETHIT;
  279.     break;
  280.  
  281.     case GM_RENDER:
  282.         retval = dial_render( g, msg );
  283.     break;
  284.  
  285.     case GM_GOINACTIVE:
  286.     /*
  287.      * since this gadget doesn't have any special allocations
  288.      * or processing when it is made active, this function
  289.      * is a no-op
  290.      */
  291.         retval = 0;
  292.     break;
  293.  
  294.     case GM_GOACTIVE:        /* first input event        */
  295.     case GM_HANDLEINPUT:    /* subsequent input events    */
  296.         retval = dial_handleinput( g, msg );
  297.     break;
  298.     }
  299.     return ( retval );
  300. }
  301.  
  302. /*
  303.  * this implementation has no highlighting visuals.
  304.  * so, if redraw is 0, I don't draw at all.
  305.  * Note that I use this function to update the visuals
  306.  * in dial_handleinput, in which case a NULL hook is passed.
  307.  * This would change if you wanted some more subtle incremental
  308.  * changing while the mouse was moved.
  309.  */
  310. static ULONG
  311. dial_render( g, msg )
  312. struct Gadget    *g;
  313. struct gpRender    *msg;
  314. {
  315.     ULONG dial_realrender();
  316.  
  317.     return( dial_realrender( g, msg->gpr_GInfo,
  318.             msg->gpr_RPort, msg->gpr_Redraw ) );
  319. }
  320.  
  321. static ULONG
  322. dial_realrender( g, gi, rp, redraw )
  323. struct Gadget        *g;
  324. struct GadgetInfo    *gi;
  325. struct RastPort        *rp;
  326. LONG            redraw;
  327. {
  328.     /* this code uses the gadget select box as is, therefore,
  329.      * this gadget doesn't support relative positioning or dimensions
  330.      */
  331.  
  332.     if ( redraw )
  333.     {
  334.         DrawImage( rp, g->GadgetRender, g->LeftEdge, g->TopEdge );
  335.     drawNeedle( rp, g, g->LeftEdge, g->TopEdge );
  336.     }
  337.  
  338.     return ( 0 );
  339. }
  340.  
  341.  
  342. static ULONG
  343. dial_handleinput( g, msg )
  344. struct Gadget    *g;
  345. struct gpInput    *msg;
  346. {
  347.     struct GadgetInfo    *gi = msg->gpi_GInfo;
  348.     struct RastPort    *ObtainGIRPort();
  349.     struct RastPort    *rp;
  350.     Point        mouse;
  351.     ULONG        retval = 0;
  352.     struct InputEvent    *ie = msg->gpi_IEvent;
  353.  
  354.     if ( ie->ie_Class == IECLASS_RAWMOUSE )
  355.     {
  356.     mouse.x = msg->gpi_Mouse.X;
  357.     mouse.y = msg->gpi_Mouse.Y;
  358.  
  359.     /* only redraw if it has moved    */
  360.     if ( SetDialCoords( g,
  361.         mouse.x - CENTER( g->Width ), mouse.y - CENTER( g->Height ) ) )
  362.     {
  363.         /* you have to ask permission to use the right rastport
  364.          * if it isn't provided in the message packet (gpRender
  365.          * is the only case of that).
  366.          */
  367.         rp = ObtainGIRPort( gi );
  368.  
  369.         /* render it with new coord values    */
  370.         dial_realrender( g, gi, rp, 1L );
  371.  
  372.         ReleaseGIRPort( rp );
  373.     }
  374.  
  375.     /* determine if we are done    */
  376.  
  377.     /* menu button: abort, input reused    */
  378.     if ( ie->ie_Code == IECODE_RBUTTON )
  379.     {
  380.         *msg->gpi_Termination = 1;    /* aborted by menu button    */
  381.         retval = GMR_REUSE | GMR_VERIFY;
  382.     }
  383.     /* select up: user is done, don't reuse input event    */
  384.     else  if ( ie->ie_Code == (IECODE_LBUTTON | IECODE_UP_PREFIX ) )
  385.     {
  386.         *msg->gpi_Termination = 0;    /* normal termination */
  387.         retval = GMR_NOREUSE | GMR_VERIFY;
  388.     }
  389.     }
  390.  
  391.     D( kprintf( "d_hi returning: %lx\n", retval ) );
  392.     return ( retval );
  393. }
  394.